/*
	Copyright (c) 2004-2006, The Dojo Foundation
	All Rights Reserved.

	Licensed under the Academic Free License version 2.1 or above OR the
	modified BSD license. For more information on Dojo licensing, see:

		http://dojotoolkit.org/community/licensing.shtml
*/


dojo.provide("dojo.widget.TreeLoadingController");

dojo.require("dojo.widget.TreeBasicController");
dojo.require("dojo.event.*");
dojo.require("dojo.json")
dojo.require("dojo.io.*");


dojo.widget.defineWidget("dojo.widget.TreeLoadingController", dojo.widget.TreeBasicController, {
	RPCUrl: "",

	RPCActionParam: "action", // used for GET for RPCUrl


	/**
	 * Common RPC error handler (dies)
	*/
	RPCErrorHandler: function(type, obj, evt) {
		alert( "RPC Error: " + (obj.message||"no message"));
	},

	preventCache: true,

	getRPCUrl: function(action) {

		// RPCUrl=local meant SOLELY for DEMO and LOCAL TESTS.
		// May lead to widgetId collisions
		if (this.RPCUrl == "local") {
			var dir = document.location.href.substr(0, document.location.href.lastIndexOf('/'));
			var localUrl = dir+"/"+action;
			//dojo.debug(localUrl);
			return localUrl;
		}

		if (!this.RPCUrl) {
			dojo.raise("Empty RPCUrl: can't load");
		}

		return this.RPCUrl + ( this.RPCUrl.indexOf("?") > -1 ? "&" : "?") + this.RPCActionParam+"="+action;
	},


	/**
	 * Add all loaded nodes from array obj as node children and expand it
	*/
	loadProcessResponse: function(node, result, callObj, callFunc) {

		if (!dojo.lang.isUndefined(result.error)) {
			this.RPCErrorHandler("server", result.error);
			return false;
		}

		//dojo.debugShallow(result);

		var newChildren = result;

		if (!dojo.lang.isArray(newChildren)) {
			dojo.raise('loadProcessResponse: Not array loaded: '+newChildren);
		}

		for(var i=0; i<newChildren.length; i++) {
			// looks like dojo.widget.manager needs no special "add" command
			newChildren[i] = dojo.widget.createWidget(node.widgetType, newChildren[i]);
			node.addChild(newChildren[i]);
		}


		//node.addAllChildren(newChildren);

		node.state = node.loadStates.LOADED;

		//dojo.debug(callFunc);

		if (dojo.lang.isFunction(callFunc)) {
			callFunc.apply(dojo.lang.isUndefined(callObj) ? this : callObj, [node, newChildren]);
		}
		//this.expand(node);
	},

	getInfo: function(obj) {
		return obj.getInfo();
	},

	runRPC: function(kw) {
		var _this = this;

		var handle = function(type, data, evt) {
			// unlock BEFORE any processing is done
			// so errorHandler may apply locking
			if (kw.lock) {
				dojo.lang.forEach(kw.lock,
					function(t) { t.unlock() }
				);
			}

			if(type == "load"){
				kw.load.call(this, data);
			}else{
				this.RPCErrorHandler(type, data, evt);
			}

		}

		if (kw.lock) {
			dojo.lang.forEach(kw.lock,
				function(t) { t.lock() }
			);
		}


		dojo.io.bind({
			url: kw.url,
			/* I hitch to get this.loadOkHandler */
			handle: dojo.lang.hitch(this, handle),
			mimetype: "text/json",
			preventCache: _this.preventCache,
			sync: kw.sync,
			content: { data: dojo.json.serialize(kw.params) }
		});
	},



	/**
	 * Load children of the node from server
	 * Synchroneous loading doesn't break control flow
	 * I need sync mode for DnD
	*/
	loadRemote: function(node, sync, callObj, callFunc){
		var _this = this;

		var params = {
			node: this.getInfo(node),
			tree: this.getInfo(node.tree)
		};

		//dojo.debug(callFunc)

		this.runRPC({
			url: this.getRPCUrl('getChildren'),
			load: function(result) {
				_this.loadProcessResponse(node, result, callObj, callFunc) ;
			},
			sync: sync,
			lock: [node],
			params: params
		});

	},


	expand: function(node, sync, callObj, callFunc) {

		if (node.state == node.loadStates.UNCHECKED && node.isFolder) {

			this.loadRemote(node, sync,
				this,
				function(node, newChildren) {
					this.expand(node, sync, callObj, callFunc);
				}
			);

			return;
		}

		dojo.widget.TreeBasicController.prototype.expand.apply(this, arguments);

	},



	doMove: function(child, newParent, index) {
		/* load nodes into newParent in sync mode, if needed, first */
		if (newParent.isTreeNode && newParent.state == newParent.loadStates.UNCHECKED) {
			this.loadRemote(newParent, true);
		}

		return dojo.widget.TreeBasicController.prototype.doMove.apply(this, arguments);
	},


	doCreateChild: function(parent, index, data, callObj, callFunc) {

		/* load nodes into newParent in sync mode, if needed, first */
		if (parent.state == parent.loadStates.UNCHECKED) {
			this.loadRemote(parent, true);
		}

		return dojo.widget.TreeBasicController.prototype.doCreateChild.apply(this, arguments);
	}



});
